using System;
using System.ComponentModel;
using System.Threading;
using System.Text.Json.Serialization;

namespace DownloadTool
{
    public class DownloadTask : INotifyPropertyChanged
    {
        private string _fileName = string.Empty;
        private double _progress;
        private string _status = string.Empty;
        private long _downloadedBytes;
        private long _totalBytes;
        private DateTime _startTime;
        private DateTime? _completedTime;
        private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
        private bool _isPaused;

        public string Id { get; set; } = string.Empty;
        public string Url { get; set; } = string.Empty;
        public string SavePath { get; set; } = string.Empty;
        public string FilePath { get; set; } = string.Empty;

        public string FileName
        {
            get => _fileName;
            set
            {
                _fileName = value;
                OnPropertyChanged(nameof(FileName));
            }
        }

        public double Progress
        {
            get => _progress;
            set
            {
                _progress = value;
                OnPropertyChanged(nameof(Progress));
                OnPropertyChanged(nameof(ProgressText));
            }
        }

        public string Status
        {
            get => _status;
            set
            {
                _status = value;
                OnPropertyChanged(nameof(Status));
            }
        }

        public long DownloadedBytes
        {
            get => _downloadedBytes;
            set
            {
                _downloadedBytes = value;
                OnPropertyChanged(nameof(DownloadedBytes));
                OnPropertyChanged(nameof(SizeText));
                OnPropertyChanged(nameof(ProgressText));
            }
        }

        public long TotalBytes
        {
            get => _totalBytes;
            set
            {
                _totalBytes = value;
                OnPropertyChanged(nameof(TotalBytes));
                OnPropertyChanged(nameof(SizeText));
                OnPropertyChanged(nameof(ProgressText));
            }
        }

        public DateTime StartTime
        {
            get => _startTime;
            set
            {
                _startTime = value;
                OnPropertyChanged(nameof(StartTime));
            }
        }

        public DateTime? CompletedTime
        {
            get => _completedTime;
            set
            {
                _completedTime = value;
                OnPropertyChanged(nameof(CompletedTime));
            }
        }

        public CancellationTokenSource CancellationTokenSource
        {
            get => _cancellationTokenSource;
            set => _cancellationTokenSource = value;
        }
        
        public bool IsPaused
        {
            get => _isPaused;
            set
            {
                _isPaused = value;
                OnPropertyChanged(nameof(IsPaused));
                OnPropertyChanged(nameof(CanPause));
                OnPropertyChanged(nameof(CanResume));
            }
        }
        
        public bool CanPause => !IsPaused && Status == "正在下载...";
        
        public bool CanResume => IsPaused;

        public string SizeText
        {
            get
            {
                if (TotalBytes > 0)
                {
                    return $"{FormatFileSize(DownloadedBytes)} / {FormatFileSize(TotalBytes)}";
                }
                else
                {
                    return FormatFileSize(DownloadedBytes);
                }
            }
        }

        public string ProgressText
        {
            get
            {
                if (TotalBytes > 0)
                {
                    return $"{Progress:F1}%";
                }
                else
                {
                    return "未知";
                }
            }
        }

        public DownloadTask()
        {
            Id = Guid.NewGuid().ToString();
            StartTime = DateTime.Now;
            Status = "准备中";
            _cancellationTokenSource = new CancellationTokenSource();
        }

        private string FormatFileSize(long bytes)
        {
            string[] suffixes = { "B", "KB", "MB", "GB", "TB" };
            int counter = 0;
            decimal size = bytes;

            while (size >= 1024 && counter < suffixes.Length - 1)
            {
                size /= 1024;
                counter++;
            }

            return string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:0.##} {1}", size, suffixes[counter]);
        }

        public event PropertyChangedEventHandler? PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}